const express = require("express");
const {JSDOM} = require("jsdom");
const {Script} = require("vm");
const vm = require("vm");

/**
 * 生成核心值的计算方法==========================================================================================================================
 * */
// 获取当前时间戳
function get_now_time() {
    return Date.now()
}

// 生成指定范围内的随机数 不包括max
function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min) + min);
}

// 计算传入字符串的ASCII码之和
function add_ascii_code(U6v) {
    var p7v = 0;
    for (var f6v = 0; f6v < U6v["length"]; f6v++) {
        var lIv = U6v["charCodeAt"](f6v);
        if (lIv < 128) {
            p7v = p7v + lIv;
        }
    }
    return p7v;
}

// 传入start_time 返回[jsrf1, jsrf2]
function get_jsrf1_2(start_time) {
    var rB = function (RN) {
        var b6 = RN[0] - RN[1];
        var DE = RN[2] - RN[3];
        var k9 = RN[4] - RN[5];
        var WN = Math.sqrt(b6 * b6 + DE * DE + k9 * k9);
        return Math.floor(WN);
    };
    var c5 = Math.floor(Math.random() * 100000 + 10000);
    var bp = String(start_time * c5);
    var Pg = 0;
    var EW = [];
    var Es = bp.length >= 18 ? true : false;
    while (EW.length < 6) {
        EW.push(parseInt(bp.slice(Pg, Pg + 2), 10));
        Pg = Es ? Pg + 3 : Pg + 2;
    }
    var fr = rB(EW);
    return [c5, fr];
}

function get_ajr(start_time){
    var XM = function () {
        return Math["floor"](Math["random"]() * 100000 + 10000);
    };


    var DM = function (start_time) {
        return function I7(start_time) {
            var LY = XM();

            var L7 = parseInt(start_time / 10000, 10);
            var dO = [btoa(LY * L7), LY];
            return dO.join("|")
        };

    };
    return DM()(start_time)
}

// 传入UA,初始化时间和[mst/sst, ajr每周更新, ajt的后一位, mst/tovl]
function get_dvc(UA, bmark_time, ajr_list) {
    // 用来存放索引结果的数组
    var result_str_arr = []

    // 将传入的字符串处理后以数字形式返回
    function str_to_num(str_11) {
        var init_long_num = 5381;
        for (var i = 0; i < str_11.length; i++) {
            init_long_num = init_long_num * 33 ^ str_11.charCodeAt(i);
            // console.log(i, str_11.charCodeAt(i), init_long_num)
        }
        if (init_long_num < 0) {
            return init_long_num >>> 0
        }
        return init_long_num
    }

// 获取前面长字符串的内容
    function get_long_str(to2_long_num, bmak_str) {
        var init_str_arr = "a3cd9efghiYjklm7opqrs1uvwQxyBz2".split("")
        // var init_str_arr = ['a', '3', 'c', 'd', '9', 'e', 'f', 'g', 'h', 'i', 'Y', 'j', 'k', 'l', 'm', '7', 'o', 'p', 'q', 'r', 's', '1', 'u', 'v', 'w', 'Q', 'x', 'y', 'B', 'z', '2']
        for (var i = 0; i < init_str_arr.length; i++) {
            var val = to2_long_num[i % to2_long_num.length]
            if (val == "1") {
                result_str_arr.push(init_str_arr[i]);
            } else if (i % 3 === 0) {
                result_str_arr.push(init_str_arr[i])
            }
        }
        var result = "";
        for (var i = 0; i < bmak_str.length; i++) {
            var index = parseInt(bmak_str[i]);
            if (result_str_arr[index]) {
                result += result_str_arr[index];
            }
        }
        return result
    }

// 获取后面短字符串的内容
    function get_short_str(to2num) {
        // result_str_arr.push("z")
        // result_str_arr.push("2")
        var short_str = ""
        for (var i = 0; i < 6; i++) {
            var value = result_str_arr[i].charCodeAt(0);
            var int_value = parseInt(to2num[i]);
            var del_value = 7 * int_value ^ (value + 2);
            var cf_1 = (value << 5) | (value >> int_value);
            var cf_2 = (value << (3 * int_value)) - value;
            var long_num = cf_1 * cf_2 - del_value;
            var new_index = Math.abs(long_num % result_str_arr.length);
            short_str += result_str_arr[new_index];
        }
        return short_str
    }

    // var index_str_arr = "a3cd9efghiYjklm7opqrs1uvwQxyBz2".split("")
    // 长字符串的获取
    // 首先将0 网页初始化时间,UA后32为 0拼接 将这个内容转为二进制数
    var ua_bmark = ajr_list[3].toString().concat(bmark_time, UA.slice(-32), ajr_list[2])
    // 返回对UA和初始化时间处理后的二进制数
    var UA_bmark_time_num = str_to_num(ua_bmark)
    var UA_bmark_time_num_2 = UA_bmark_time_num.toString(2)  // 以上通过
    // 拼接时间戳信息
    var bmark_str = ajr_list[2].toString() + (bmark_time + ajr_list[0])
    // 将对UA和初始化时间得到的二进制数和时间戳信息传入get_long_str方法中得到前面16位的字符串内容
    var long_str = get_long_str(UA_bmark_time_num_2, bmark_str)
    var list_index = ajr_list[0] + ajr_list[1] + ajr_list[2]
    var list_num = str_to_num(list_index) + UA_bmark_time_num
    var list_num_2 = list_num.toString(2)
    var short_str = get_short_str(list_num_2)
    // 和时间戳及UA有关的内容  // b+e+g+d+f+i+h+c+j+l+a+
    // return (long_str + short_str + ",").concat(getRandomInt(8, 30), ",").concat('b+e+g+d+f+i+h+c+j+l+a+')
    return long_str + short_str + "," + getRandomInt(8, 30) + ","  // d+f这个字符串每个js文件不一样 f+b+j+k+i+a+e+g+l+
}

// 返回ver等每份JS会变的内容
function get_ver(dict) {
    const ver = dict["ver"]
    const din_list_key = []
    const din_list = dict['din']
    for (const value in din_list) {
        din_list_key.push(Object.keys(din_list[value])[0])
    }
    const dvc_end = dict["mst"][28]["dvc"].split(",")[2]
    return {
        "ver": ver,
        "din_list_key": din_list_key,
        "dvc": dvc_end
    }
}

// 返回屏幕分辨率[x, y]
function get_screen() {
    const screen_list = ['1280×720', '1366×768', "1536×864", "1600×900", "1920×1080", "2560×1440", "2560×1600"]
    const screen = screen_list[getRandomInt(0, screen_list.length)].split("×")
    return {x: screen[0], y: screen[1]}
}


// 返回排序后的din内容
function sort_din(sort_key, init_din) {
    let din_list = []
    for (const index in sort_key) {
        const key = sort_key[index]
        const obj = {
            [key]: init_din[key]
        }
        din_list.push(obj)
    }

    return din_list
}

/**
 * 获取字典的函数==========================================================================================================================
 * */
function get_dict(js_data, UA) {
    const pur = "https://www.goindigo.in/flights?linkNav=Flight%7CBook%7CBook"
    const start_time = get_now_time()
    const screen = get_screen()  // 形式{x : "", y : ""}
    const screen_x = parseInt(screen["x"])
    const screen_y = parseInt(screen["y"])
    // 每份JS都会变得内容
    const ver_sort_dvc_end = get_ver(js_data)
    // din_list 中要用到的值
    const hal = start_time / 2
    const hz1 = Math.floor(start_time / (2016 * 2016))
    const dd2 = Math.floor(hz1 / 23)
    const wih = getRandomInt(Math.floor(screen_y / 2), screen_y)
    const wiw = getRandomInt(Math.floor(screen_x / 2), screen_x)
    const npl = getRandomInt(1, 15)
    const nal = getRandomInt(0, 2) === 1 ? "en" : "zh-CN"
    const init_din = {
        "nps": "20030107",
        "ash": screen_y, // window['screen']['availHeight'] 屏幕可用高度
        "wih": wih,
        "asw": screen_x,
        "she": screen_y,
        "wiw": wiw,  // innerWeight
        "pha": 0,
        "ran": Math.random().toString(),
        "xag": 12147,
        "nap": "Gecko",
        "swi": screen_x,
        "tsd": 0,
        "nal": nal,
        "wdr": 0,
        "wow": wiw + getRandomInt(10, 30),  // outWeight
        "ua": UA,
        "npl": npl, // 插件数量
        "ucs": "".concat(add_ascii_code(UA)),
        "ibr": 0,
        "hz1": hz1,
        "dau": 0,
        "adp": "cpen:0,i1:0,dm:0,cwen:0,non:1,opc:0,fc:0,sc:0,wrc:1,isc:0,vib:1,bat:1,x11:0,x12:1",
        "hal": hal
    }
    // 排序后din的值
    const din = sort_din(ver_sort_dvc_end['din_list_key'], init_din)
    // mst_list 中要用到的值
    const ssts = getRandomInt(1, 15)
    const delt = ssts

    // 大字典中用到的值
    const jsrf_list = get_jsrf1_2(start_time)
    const ajr = get_ajr(start_time)
    const dvc = get_dvc(UA, start_time, [ssts, ajr, 0, 0]) + ver_sort_dvc_end["dvc"]
    let test = {
        "ver": ver_sort_dvc_end["ver"],
        "fpt": "-1",
        "fpc": "94",
        "ajr": ajr,
        "din": din,
        "eem": "do_en,dm_en,t_en",
        "ffs": "",
        "vev": "",
        "inf": "",
        "ajt": "0,0", // 次数很重要,要对的上  QAt  jLt,ZPt
        "kev": "",
        "dme": "",
        "mev": "",
        "doe": "",
        "pur": pur,
        "pev": "",
        "mst": [
            {
                "kevl": 1
            },
            {
                "mevl": 32
            },
            {
                "tevl": 32
            },
            {
                "devl": 0
            },
            {
                "dmvl": 0
            },
            {
                "pevl": 0
            },
            {
                "tovl": 0
            },
            {
                "delt": delt
            },
            {
                "it": 0
            },
            {
                "sts": start_time
            },
            {
                "fct": -999999
            },
            {
                "dd2": dd2
            },
            {
                "kc": 0
            },
            {
                "mc": 0
            },
            {
                "ww8": 0
            },
            {
                "pc": 0
            },
            {
                "tc": 0
            },
            {
                "ssts": ssts
            },
            {
                "tst": 0
            },
            {
                "rval": "-1"
            },
            {
                "rcfp": "-1"
            },
            {
                "nfas": 30261693
            },
            {
                "jsrf": "PiZtE"
            },
            {
                "jsrf1": jsrf_list[0]
            },
            {
                "jsrf2": jsrf_list[1]
            },
            {
                "signals": "0"
            },
            {
                "mwd": "0"
            },
            {
                "hea": ""
            },
            {
                "dvc": dvc
            },
            {
                "srd": "0"
            }
        ],
        "o9": 0,
        "tev": "",
        "sde": ["0,0,0,0,1,0,0", "0,0,0,0,0,0,0"][getRandomInt(0, 2)],
        "pmo": "",
        "dpw": "",
        "pac": "",
        "per": "8",
        "pde": "",
        "oev": "",
        "if": "",
        "fwd": [
            {
                "fmh": ""
            },
            {
                "fmz": ""
            },
            {
                "ssh": "0"
            }
        ],
    }
    return test
}

/**
 *  加密用的方法==========================================================================================================================
 * */
var get_bm_sz_list = function (bm_sz, encrypt_number) {
    var WM = [8888888, encrypt_number];
    var f0 = decodeURIComponent(bm_sz).split('~');
    if (f0.length >= 4) {
        var ff = parseInt(f0[2], 10);
        ff = isNaN(ff) ? 8888888 : ff;
        WM[0] = ff;
    }
    return WM
}

// 处理Akm的核心大字典,第一次
function handle_dict_first(wh7) {
    var HR7 = wh7[0];
    var UN7 = wh7[1];
    var wD7;
    var ft7;
    var hh7;
    var qA7;
    var nt7 = ':';
    var CN7 = HR7.split(nt7);
    for (qA7 = 0; qA7 < CN7.length; qA7++) {
        wD7 = ((UN7 >> 8) & 65535) % CN7.length;
        UN7 *= 65793;
        UN7 &= 4294967295;
        UN7 += 4282663;
        UN7 &= 8388607;
        ft7 = ((UN7 >> 8) & 65535) % CN7.length;
        UN7 *= 65793;
        UN7 &= 4294967295;
        UN7 += 4282663;
        UN7 &= 8388607;
        hh7 = CN7[wD7];
        CN7[wD7] = CN7[ft7];
        CN7[ft7] = hh7;
    }
    return CN7.join(nt7)
}

// 处理Akm的核心大字典,第二次
function handle_dict_second(q4, sr) {
    // 需要用到的一些初始值
    var vr = new Array(127);
    var R6 = ''
    //  R6 :   !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~
    for (var d0 = 0; d0 < 127; ++d0) {
        if (d0 < 32 || (d0 === 39) || (d0 === 34) || (d0 === 92)) {
            vr[d0] = -1;
        } else {
            vr[d0] = R6.length;
            R6 += String.fromCharCode(d0);
        }
    }
    var Gk = "";
    for (var Eh = 0; Eh < q4.length; Eh++) {
        var VG = q4.charAt(Eh);
        var UN = (sr >> 8) & 65535;
        sr *= 65793;
        sr &= 4294967295;
        sr += 4282663;
        sr &= 8388607;
        var XG = vr[q4.charCodeAt(Eh)];
        var RX = VG.codePointAt(0);
        if (RX >= 32 && RX < 127) {
            XG = vr[RX];
        }
        if (XG >= 0) {
            var GY = UN % R6.length;
            XG += GY;
            XG %= R6.length;
            VG = R6[XG];
        }
        Gk += VG;
    }
    return Gk
}

let count = 0

/**
 *  对大字典进行加密的处理内容=============================================================================================
 * */
function get_sensor(bm_sz, coreDict, encrypt_number) {
    count += 1
    console.log(`第${count}次调用=======================================================================`)
    // console.log(coreDict)
    console.log(JSON.stringify(coreDict))

    var bm_sz_list = get_bm_sz_list(bm_sz, encrypt_number);
    var encryptData = JSON.stringify(coreDict);
    var handle_dict_first_time = get_now_time();
// 对核心的大字典进行第一次处理
    encryptData = handle_dict_first([encryptData, bm_sz_list[1]]);
    handle_dict_first_time = get_now_time() - handle_dict_first_time;
    // console.log(encryptData)

    var handle_dict_second_time = get_now_time();
// 对核心大字典进行第二次处理
    encryptData = handle_dict_second(encryptData, bm_sz_list[0]);
    handle_dict_second_time = get_now_time() - handle_dict_second_time;

    var timeStampInfo = "".concat(getRandomInt(5, 25), ',').concat(getRandomInt(3, 20), ",").concat(0, ",").concat(handle_dict_first_time, ",").concat(handle_dict_second_time, ",").concat(getRandomInt(20, 100));
    var beforeEncryptData = getRandomInt(0, 2) === 0 ? ["3", "0", "1", "0", bm_sz_list[0], coreDict['ver']].join(";") : ["3", "0", "1", "2048", bm_sz_list[0], coreDict['ver']].join(";")
    encryptData = "".concat(beforeEncryptData, ';').concat(timeStampInfo, ';').concat(encryptData);
    return encryptData
}


function run_js_evn(js_data, vmContext) {
    let dict = {}
    const originalStringify = vmContext.JSON.stringify;


    vmContext.setTimeout = function () {
    }
    vmContext.setInterval = function () {
    }


    class CustomArray extends Array {
        constructor(...args) {
            super(...args);
            if (args.length === 2 && args[0] === 8888888) {
                Object.assign(dict, {"number": args[1]})
            }
        }
    }

    vmContext.CustomArray = CustomArray;

    // 重写 JSON.stringify 方法
    vmContext.JSON.stringify = function (value, replacer, space) {
        if (value !== undefined) {
            const log = Object.keys(value)
            // 在这里添加自定义逻辑
            if (log.includes("ver")) {
                Object.assign(dict, value)
            }
        }
        return originalStringify(value, replacer, space);
    }

    const script = new Script(js_data);
    script.runInContext(vmContext);

    vmContext.JSON.stringify = originalStringify;

    console.log("number", dict['number'])
    return dict
}


/**
 * 封装调用接口
 * */

function callTheAPI() {
    console.log("Akamai, 6E")
    const app = express();
    const port = 5889;
// 解析请求体
    app.use(express.json({limit: "2100000kb"}));

// 定义一个路由来返回 get_core_dict 的结果
    app.post('/getSensor', (req, res) => {
        const dom = new JSDOM(`<script type="text/javascript" src="bdn7aS/1gi/NdK/6Rsrw5JT/YVrObpVQffhr/WV47agRFFAY/TmB/rcwRUCU8"></script>`, {
            runScripts: "outside-only",
        });
        // 创建一个新的 vmContext 以确保每次调用 run_js_evn 时上下文环境一致
        const newVmContext = vm.createContext(dom.getInternalVMContext());
        let bm_sz = req.body["bm_sz"];
        const UA = req.body["UA"];
        let js_data;
        try {
            // 获取传入的这份JS文件ver内容
            js_data = run_js_evn(req.body["js"], newVmContext)
            let encrypt_number = js_data['number']
            res.send({sensor_data: get_sensor(bm_sz, get_dict(js_data, UA), encrypt_number)});
        } catch (e) {
            res.send({error: e.message});
        }
    });

    app.listen(port, () => {
        console.log(`Server is running on http://localhost:${port}/getSensor`);
    });
}


callTheAPI()


